# https://docs.python-requests.org/zh_CN/latest/user/quickstart.html#id9
import requests
from requests import cookies
# 发送一个post请求
# 发送请求
response = requests.get('https://api.github.com')
# 状态码
status_code = response.status_code
print(status_code)

# 传递url参数：Requests 允许使用 params 关键字参数，以一个字符串字典来提供这些参数。注意字典里值为 None 的键都不会被添加到 URL 的查询字符串里。
payload={'key1':'value1','key2':'value2'}
r = requests.get('http://httpbin.org/get',params=payload)
print(r.url)
# 将一个列表作为值传入
payload = {'key1':'value1','key2':['value2','value3']}
r = requests.get('http://httpbin.org/get',params=payload)
print(r.url)

# 响应内容
r = requests.get('https://api.github.com/events')
# print(r.text) #读取响应内容
# 编码格式
print(r.encoding)
# 改变编码格式：r.encoding='ISO-8859-1'

# 二进制响应内容：Requests 会自动为你解码 gzip 和 deflate 传输编码的响应数据。
# print(r.content)

# JSON响应内容
# print(r.json())
# 如果 JSON 解码失败， r.json() 就会抛出一个异常。例如，响应内容是 401 (Unauthorized)，尝试访问 r.json() 将会抛出 ValueError: No JSON object could be decoded 异常。
# 需要注意的是，成功调用 r.json() 并**不**意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象（比如 HTTP 500 的错误细节）。这种 JSON 会被解码返回。要检查请求是否成功，请使用 r.raise_for_status() 或者检查 r.status_code 是否和你的期望相同。
print(r.raise_for_status)

# 原始响应内容
r = requests.get('https://api.github.com/events',stream=True)
print(r.raw) # 想获取来自服务器的原始套接字响应，那么你可以访问 r.raw。 如果你确实想这么干，那请你确保在初始请求中设置了 stream = True。
print(r.raw.read(10))

# 更加复杂post请求：发送一些编码为表单形式的数据——非常像一个 HTML 表单。要实现这个，只需简单地传递一个字典给 data 参数。
payload = {'key1':'value1','key2':'value2'}
r = requests.post('http://httpbin.org/post',data=payload)
print(r.text)
# 可以为 data 参数传入一个元组列表。在表单中多个元素使用同一 key 的时候，这种方式尤其有效：
payload = (('key1','value1'),('key2','value2'))
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)
# 想要发送的数据并非编码为表单形式的。如果你传递一个 string 而不是一个 dict，那么数据会被直接发布出去。
url = 'https://api.github.com/some/endpint'
payload = {'some':'data'}
import json
r = requests.post(url,data=json.dumps(payload))
print(r.text)
# 此处除了可以自行对 dict 进行编码，你还可以使用 json 参数直接传递，然后它就会被自动编码。
r = requests.post(url,json=payload)
print(r.text)

# POST一个多部分编码(Multipart-Encoded)的文件
url = 'https://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
print(r.text)
# 可以显式地设置文件名，文件类型和请求头：
files = {'files': ('report.xls', open('report.xls', 'rb'),'application/vnd.ms-excel', {'Expires': '0'})}
r = requests.post(url, files=files)
print(r.text)
# 可以发送作为文件来接收的字符串
files = {'files': ('report.csv','some,data,to,send\nanother,row,to,send\n')}
r = requests.post(url,files=files)
print(r.text)

# 响应状态码
r = requests.get('http://httpbin.org/get')
print(r.status_code)
print(r.status_code == requests.codes.ok)
# 如果发送了一个错误请求(一个 4XX 客户端错误，或者 5XX 服务器错误响应)，我们可以通过 Response.raise_for_status() 来抛出异常：
bad_r =requests.get('http://httpbin.org/status/404')
print(bad_r.status_code)

# 响应头
print(r.headers)
# HTTP 头部是大小写不敏感的。
print(r.headers['Content-Type'])
print(r.headers['content-type'])

# Cookie
url ='http://example.com/some/cookie/setting/url'
r = requests.get(url)
print(r.cookies)
# 发送你的cookies到服务器，可以使用cookies参数
url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are = 'working')
r = requests.get(url,cookies=cookies)
print(r.text)
# Cookie 的返回对象为 RequestsCookieJar，它的行为和字典类似，但接口更为完整，适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 Requests 中：
jar = requests.cookies.RequestsCookieJar()
jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
url = 'http://httpbin.org/cookies'
r = requests.get(url, cookies=jar)
print(r.text)

# 重定向与请求历史
# 默认情况下，除了 HEAD, Requests 会自动处理所有重定向。可以使用响应对象的 history 方法来追踪重定向。
# Response.history 是一个 Response 对象的列表，为了完成请求而创建了这些对象。这个对象列表按照从最老到最近的请求进行排序。
# 例如，Github 将所有的 HTTP 请求重定向到 HTTPS：
r =requests.get('http://github.com')
print(r.url)
print(r.status_code)
print(r.history)
# 如果你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE，那么你可以通过 allow_redirects 参数禁用重定向处理：
r = requests.get('http://github.com',allow_redirects=False)
print(r.status_code)
print(r.history)
# 使用了 HEAD，也可以启用重定向：
r = requests.head('http://github.com', allow_redirects=False)
print(r.url)
print(r.history)

# 超时：requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用，你的程序可能会永远失去响应：
# requests.get('http://github.com',timeout=0.001)
# 注意
# timeout 仅对连接过程有效，与响应体的下载无关。 timeout 并不是整个下载响应的时间限制，而是如果服务器在 timeout 秒内没有应答，
# 将会引发一个异常（更精确地说，是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时）If no timeout is specified explicitly, requests do not time out.

# 错误与异常
# 遇到网络问题（如：DNS 查询失败、拒绝连接等）时，Requests 会抛出一个 ConnectionError 异常。
# 如果 HTTP 请求返回了不成功的状态码， Response.raise_for_status() 会抛出一个 HTTPError 异常。
# 若请求超时，则抛出一个 Timeout 异常。
# 若请求超过了设定的最大重定向次数，则会抛出一个 TooManyRedirects 异常。
# 所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 。
